/*
 **************************************************************************************
 *                        桂林光通电子工程公司
 *
 *  文件描述： Otdr计算主文件。使用在Otdr模块上
 *
 *  文件名  ： OTDR.c
 *  创建者  ： 彭怀敏
 *  创建日期： 2011-4-2 16:30:14
 *  当前版本： v1.0
 * 
 ***** 修改记录 *****
 *  修改者  ： 
 *  修改日期： 
 *  备    注： 
 **************************************************************************************
*/
#include <stdio.h>
#include <assert.h>
#include "Otdr.h"
#include "OtdrSpiData.h"
#include "prototypes.h"

#if TR600_A_CLASS
    #undef  MIN_PW_DATA_CONCAT
    #define MIN_PW_DATA_CONCAT     2560
#else
    #undef  MIN_PW_DATA_CONCAT
    #define MIN_PW_DATA_CONCAT     640
#endif

// 判断拼接的条件
#define CC  ((StateCtrl->MeasureParam.PulseWidth_ns >= MIN_PW_DATA_CONCAT) && \
            (StateCtrl->MeasureParam.MeasureLength_m >= 100000))
            
/*
 **************************************************************************************
 *  函数名称： GetCurveStartPoint
 *  函数描述： 读取该量程下的曲线起始点
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2011-3-21 17:05:12
 **************************************************************************************
*/
static int GetCurveStartPoint(int ml)
{
    int i = GetMeasureLengthIndex(ml);
    return OtdrStartPoint[i];
}

/*
 **************************************************************************************************
 *  函数  名： AdaptSampleFreq_PulsePeriod
 *  函数描述： 根据光纤长度匹配采样率和脉冲周期
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2011-05-30  08:42:13  v1.0
 **************************************************************************************************
*/
void AdaptSampleFreq_PulsePeriod(OtdrStateCtrl_t *StateCtrl)
{
    int MeasureLength_m = StateCtrl->MeasureParam.MeasureLength_m;
    int index, clk_num;
    
    index   = GetMeasureLengthIndex(MeasureLength_m);
    clk_num = OtdrSampleRate[index] / CLK_50MHz;
    clk_num = MAX(clk_num, 1);
    
    StateCtrl->RealSampleRate_MHz = OtdrSampleRate[index];
    StateCtrl->RealSampleRate_Hz  = OtdrSampleRateHz[index];
    StateCtrl->PulsePeriod_us      = OtdrPulsePeriod[index];
}

/*
 **************************************************************************************************
 *  函数  名： PowerModeInit
 *  函数描述： 初始化功率控制模式
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2013-01-04  16:17:21  v1.0
 **************************************************************************************************
*/
static void PowerModeInit(OtdrStateCtrl_t *StateCtrl)
{
    if(CC)
    {
        if(OTDR_MODE_REALTIME == StateCtrl->OtdrMode)
        {
            StateCtrl->ConcatParam.PowerMode = POWER_MODE_LOW;    // 实时模式功率控制模式为低
        }
        else    StateCtrl->ConcatParam.PowerMode = POWER_MODE_UNDEF;  // 其他为未定义功率控制模式
        StateCtrl->ConcatParam.PowerMode = POWER_MODE_UNDEF;  // 其他为未定义功率控制模式
    }
    else        StateCtrl->ConcatParam.PowerMode = POWER_MODE_HIGH;
}

/*
 **************************************************************************************************
 *  函数  名： AdaptMeasureLength_PulseWidth
 *  函数描述： 根据光纤长度自动匹配量程和脉宽
 *  入口参数： FiberLen : 光纤长度
 *  返回参数： 
 *  日期版本： 2011-05-08  21:18:49  v1.0
 **************************************************************************************************
*/
void AdaptMeasureLength_PulseWidth(int FiberLen, OtdrStateCtrl_t *StateCtrl)
{
    int i, j, PulseWidth_ns;
    float   v = StateCtrl->AutoEndLevel;
    
    FiberLen = 1.5*FiberLen;    // 2011-9-16 10:13:26
    for(i = 0; i < MEASURE_LENGTH_NUM-1; i++)
    {
        if(FiberLen <= OtdrMeasureLength[i])    break;
    }
    
    StateCtrl->MeasureParam.MeasureLength_m = OtdrMeasureLength[i];
    StateCtrl->MeasureParam.PulseWidth_ns   = OtdrDefaultPulseWidth[i];
    
    if(StateCtrl->EnableAutoPulseWidth)   // 自动匹配脉宽
    {
        if(v <= 5)          j = 0;
        else if(v <= 9)     j = 1;
        else if(v <= 13)    j = 2;
        else if(v <= 17)    j = 3;
        else if(v <= 21)    j = 4;
        else                j = 5;
        
        PulseWidth_ns = OtdrDefaultPulseWidth_AUTO[i][j];
        StateCtrl->MeasureParam.PulseWidth_ns = PulseWidth_ns;
    }

    // 自动更新采样率和脉冲周期
    AdaptSampleFreq_PulsePeriod(StateCtrl);
    
    // 初始化功率控制模式
    PowerModeInit(StateCtrl);
}

/*
 **************************************************************************************************
 *  函数  名： ModifyMeasureLength_PulseWidth
 *  函数描述： 修正量程和脉宽
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2011-07-06  12:01:42  v1.0
 **************************************************************************************************
*/
static void ModifyMeasureLength_PulseWidth(OtdrStateCtrl_t *StateCtrl)
{
    int i, MeasureLength_m, PulseWidth_ns;
    
    MeasureLength_m = StateCtrl->MeasureParam.MeasureLength_m;
    PulseWidth_ns   = StateCtrl->MeasureParam.PulseWidth_ns;
    
    // 如果脉宽低于10，则定为5；如果脉宽低于20，则定为10；否则必须为20的倍数
    if(PulseWidth_ns < 10)
    {
        PulseWidth_ns = 5;
    }
    else if(PulseWidth_ns < 20)
    {
        PulseWidth_ns = 10;
    }
    else
    {
        PulseWidth_ns = (PulseWidth_ns / 20) * 20;
    }

    // 把量程向上修正为默认量程选项
    MeasureLength_m = MAX(MeasureLength_m, OtdrMeasureLength[0]);
    MeasureLength_m = MIN(MeasureLength_m, OtdrMeasureLength[MEASURE_LENGTH_NUM-1]);
    for(i = 0; i < MEASURE_LENGTH_NUM; i++)
    {
        if(MeasureLength_m <= OtdrMeasureLength[i])
        {
            MeasureLength_m = OtdrMeasureLength[i];
            break;
        }
    }
    
    StateCtrl->MeasureParam.MeasureLength_m = MeasureLength_m;
    StateCtrl->MeasureParam.PulseWidth_ns   = PulseWidth_ns;
}

/*
 ********************************************************************************
 *  函数名称 ： GetReceiverAndPowerLevel
 *  函数描述 ： 获取功率控制级别
 *  入口参数 ： cp               : concat parameter
 *              TotalMeasureTime : total measure time currently
 *  返回参数 ： rcv   : 返回的Rcv from cp
 *              power : power from cp
 *  日期版本 ： 2016-10-24 11:05:36
 ********************************************************************************
*/
int getApdV(OtdrStateCtrl_t *StateCtrl)
{
    extern float TemperatureDivision[8];
    extern Uint8 ApdVBitmap[8];

    int i, t, apdv;
    float apdt;

#if DATA_SPI
    getTemperature(&t);
#else
    t = 30000;
#endif

    apdt = t / 1000.0;
    m1_print("apdt = %.3f\n", apdt);
    for(i = 0; i < 8; i++){
        if(apdt <= TemperatureDivision[i])  break;
    }
    apdv = ApdVBitmap[i];

    if(StateCtrl != NULL)   StateCtrl->thisApdV = apdv;

    return apdv;
}

void GetReceiverAndPowerLevel(OtdrStateCtrl_t *StateCtrl, int TotalMeasureTime, int *rcv, int *power)
{
    int lowt;
    unsigned int r;
    
    StateCtrl->TreatAsHighPowerData = 1;
    if(StateCtrl->ConcatParam.PowerMode == POWER_MODE_HIGH){
        *rcv = StateCtrl->ConcatParam.HighRcv;
        *power = StateCtrl->ConcatParam.HighPower;
    }
    else if(StateCtrl->ConcatParam.PowerMode == POWER_MODE_LOW){
        *rcv = StateCtrl->ConcatParam.LowRcv;
        *power = StateCtrl->ConcatParam.LowPower;
    }
    else{    // StateCtrl->ConcatParam.PowerMode = POWER_MODE_CONCAT
        if(StateCtrl->OtdrMode == OTDR_MODE_REALTIME){
            lowt = StateCtrl->RefreshPeriod_ms/2;
            TotalMeasureTime = (TotalMeasureTime % StateCtrl->RefreshPeriod_ms);
        }
        else{
            lowt = StateCtrl->MeasureParam.MeasureTime_ms / 4;
            lowt = MAX(lowt, 2000);     // at least 2s
            lowt = MIN(lowt, 10000);    // at most 10s
        }

        if(TotalMeasureTime < lowt){
            *rcv = StateCtrl->ConcatParam.LowRcv;
            *power = StateCtrl->ConcatParam.LowPower;
            StateCtrl->TreatAsHighPowerData = 0;
        }
        else{  
            *rcv = StateCtrl->ConcatParam.HighRcv;
            *power = StateCtrl->ConcatParam.HighPower;
        }
    }

    StateCtrl->thisRcv = *rcv;
    StateCtrl->thisPower = *power;

    r = *rcv;
    if(r == 0x70)           StateCtrl->TailLength = 1000;
    else if(r == 0x78)      StateCtrl->TailLength = 1500;
    else if(r == 0xB0)      StateCtrl->TailLength = 2000;
    else if(r == 0xD0)      StateCtrl->TailLength = 3000;
    else if(r == 0xD8)      StateCtrl->TailLength = 5000;
    else                    StateCtrl->TailLength = 6000;
}

/*
 **************************************************************************************************
 *  函数  名： OtdrStateInit
 *  函数描述： 初始化OtdrState里的相关量，它必须在自动测试完成后，即完全确定量程脉宽后调用
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2012-12-27  15:13:33  v1.0
 **************************************************************************************************
*/
void OtdrStateInit(OtdrStateCtrl_t *StateCtrl)
{
    int MeasureLength_m, PulseWidth_ns;
    
    MeasureLength_m = StateCtrl->MeasureParam.MeasureLength_m;
    PulseWidth_ns = StateCtrl->MeasureParam.PulseWidth_ns;
    
    StateCtrl->TreatAsHighPowerData = 1;

	StateCtrl->M = PulseWidthInSampleNum(StateCtrl);
	StateCtrl->Points_1m = 2*StateCtrl->MeasureParam.n * StateCtrl->RealSampleRate_Hz /C;
//	if(MeasureLength_m > 60000)
//    {
//        if(PulseWidth_ns > 10240)           StateCtrl->MinNoiseAmp = -8;
//        else if(PulseWidth_ns > 5120)       StateCtrl->MinNoiseAmp = -7;
//        else if(PulseWidth_ns > 2560)       StateCtrl->MinNoiseAmp = -6;
//        else                                StateCtrl->MinNoiseAmp = -5;
//    }
//    else    StateCtrl->MinNoiseAmp = -5;
    StateCtrl->MinNoiseAmp = -5;

    if(StateCtrl->MeasureParam.MeasureLength_m == 100000)
        StateCtrl->MeasureLengthPoint = StateCtrl->DataNum - NOISE_NUM;
    else
        StateCtrl->MeasureLengthPoint = StateCtrl->MeasureParam.MeasureLength_m * StateCtrl->Points_1m;

    StateCtrl->CurveStartPoint = GetCurveStartPoint(StateCtrl->MeasureParam.MeasureLength_m);
}

/*
 **************************************************************************************************
 *  函数  名： OtdrUpdateParam
 *  函数描述： 更新OtdrCtrl和OtdrState参数。它在开始测试前调用，以确保参数的正确性，并复制
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2011-04-27  10:30:41  v1.0
 **************************************************************************************************
*/
void OtdrUpdateParam(OtdrStateCtrl_t *StateCtrl, OtdrTestParam_t *tp)
{
    int temp;
/************************************** 更新 StateCtrl ********************************************/
    StateCtrl->OtdrMode = tp->OtdrMode;
    StateCtrl->DataNum = tp->DataNum;
    StateCtrl->RefreshPeriod_ms = tp->RefreshPeriod_ms;
    StateCtrl->RawDataLevel = 0x7fff;
    StateCtrl->EnableAutoPulseWidth = 1;
    
    StateCtrl->LowPowerDataChanged = 0;
    
    StateCtrl->PulsePeriod_us = 1000;
	StateCtrl->FpgaTimeOut = 0;

    temp = tp->slice_ms;
    temp = MAX(temp, 100);
    temp = MIN(temp, 1000);
    temp = temp / 100 * 100;    // 100的倍数
    StateCtrl->slice_ms = temp;
    
    // 状态指示
    StateCtrl->OtdrAlgoBusyNow = 0;    // 正在进行数据处理     bool
    
    // 模式确定
    if(0 == tp->MeasureLength_m)    StateCtrl->MeasureMode = MEASURE_MODE_AUTO;
    else                            StateCtrl->MeasureMode = MEASURE_MODE_MANUAL;
    
/************************************** 初始化 StateCtrl.Measureparam *****************************************/
   	StateCtrl->MeasureParam.ChanNum         = tp->ChanNum;
   	StateCtrl->MeasureParam.Lambda_nm       = tp->Lambda_nm;
   	StateCtrl->MeasureParam.MeasureLength_m = tp->MeasureLength_m;
   	StateCtrl->MeasureParam.PulseWidth_ns   = tp->PulseWidth_ns;
   	StateCtrl->MeasureParam.MeasureTime_ms  = tp->MeasureTime_ms;
   	StateCtrl->MeasureParam.n               = tp->n;
   	StateCtrl->MeasureParam.EndThreshold    = tp->EndThreshold;
   	StateCtrl->MeasureParam.NonReflex       = tp->NonReflex;
    
    // 记录上位机设定的波长和脉宽作副本
    StateCtrl->RcvLambda = StateCtrl->MeasureParam.Lambda_nm;
    StateCtrl->RcvPw     = StateCtrl->MeasureParam.PulseWidth_ns;

    // 更新量程和脉宽
    if(MEASURE_MODE_AUTO == StateCtrl->MeasureMode)       // 自动测试
    {
        if((850 == StateCtrl->MeasureParam.Lambda_nm) || (1300 == StateCtrl->MeasureParam.Lambda_nm))
        {
            StateCtrl->MeasureParam.MeasureLength_m = 30000; // 30km
            StateCtrl->MeasureParam.PulseWidth_ns   = 640;   // 640ns
        }
        else
        {
            StateCtrl->MeasureParam.MeasureLength_m = OtdrAutoMeasureParam[0][0];
            StateCtrl->MeasureParam.PulseWidth_ns   = OtdrAutoMeasureParam[1][0];
        }
    }
    else
    {
        // 根据光纤长度匹配采样率和脉冲周期
        ModifyMeasureLength_PulseWidth(StateCtrl);
        AdaptSampleFreq_PulsePeriod(StateCtrl);

        // 初始化功率控制模式
        PowerModeInit(StateCtrl);
        OtdrStateInit(StateCtrl);
    }
    
    // 更新结束门限和非反射门限
    StateCtrl->MeasureParam.EndThreshold = MAX(StateCtrl->MeasureParam.EndThreshold, 3);
    if(NR_MODE_MANUAL == StateCtrl->MeasureParam.NonReflex)      // 自动
    {
        StateCtrl->MeasureParam.NonReflex = MAX(StateCtrl->MeasureParam.NonReflex, 0.01);
    }
    
    // 调整刷新周期, FPGA时间片slice_ms必须小于等于刷新周期
    temp = StateCtrl->RefreshPeriod_ms;
    temp = MAX(temp, 1000);
    temp = (temp + 999) / 1000 * 1000;    // 向上取整，1000的倍数
    StateCtrl->RefreshPeriod_ms = temp;
    StateCtrl->slice_ms = MIN(StateCtrl->slice_ms, temp);
    
    // 调整测试时间,单次模式下必须大于刷新周期
    if(OTDR_MODE_AVG == StateCtrl->OtdrMode)
    {
        temp = StateCtrl->MeasureParam.MeasureTime_ms;
        temp = MIN(temp, 180000);
        temp = MAX(temp, 1000);
        temp = (temp + 999) / 1000 * 1000;    // 向上取整，1000的倍数
        StateCtrl->MeasureParam.MeasureTime_ms = temp;
    }
    // 实时模式下为刷新周期
    else if(OTDR_MODE_REALTIME == StateCtrl->OtdrMode)
    {
        StateCtrl->MeasureParam.MeasureTime_ms = StateCtrl->RefreshPeriod_ms;
    }
    else if(OTDR_MODE_CYCLE_TEST != StateCtrl->OtdrMode)
    {
        StateCtrl->MeasureParam.MeasureTime_ms = 15000;
    }
}

void OtdrUpdateParamAutoAdapt(OtdrStateCtrl_t *StateCtrl, OtdrTestParam_t *tp)
{
/************************************** 更新 StateCtrl ********************************************/
   	StateCtrl->OtdrMode    = tp->OtdrMode;
    StateCtrl->DataNum = tp->DataNum;
	StateCtrl->FpgaTimeOut = 0;
    
/******************************** 初始化 StateCtrl.Measureparam ***********************************/
   	StateCtrl->MeasureParam.ChanNum         = tp->ChanNum;
   	StateCtrl->MeasureParam.Lambda_nm       = tp->Lambda_nm;

    // if measurelegnth is NOT 0, then do NOTHING
    if(tp->MeasureLength_m == 0){
        StateCtrl->MeasureParam.MeasureLength_m = OtdrAutoMeasureParam[0][0];   // Auto measure param
        StateCtrl->MeasureParam.PulseWidth_ns   = OtdrAutoMeasureParam[1][0];
    }
    else{
        StateCtrl->MeasureParam.MeasureLength_m = tp->MeasureLength_m;   // Auto measure param
        StateCtrl->MeasureParam.PulseWidth_ns   = tp->PulseWidth_ns;
    }
   	StateCtrl->MeasureParam.MeasureTime_ms  = 400;
   	StateCtrl->MeasureParam.n               = tp->n;
   	StateCtrl->MeasureParam.EndThreshold    = tp->EndThreshold;
   	StateCtrl->MeasureParam.NonReflex       = tp->NonReflex;
    
    // 根据光纤长度匹配采样率和脉冲周期
    AdaptSampleFreq_PulsePeriod(StateCtrl);
    PowerModeInit(StateCtrl);
    OtdrStateInit(StateCtrl);
}

void OtdrUpdateParamEstimateConcat(OtdrStateCtrl_t *StateCtrl, OtdrTestParam_t *tp)
{
/************************************** 更新 StateCtrl ********************************************/
   	StateCtrl->OtdrMode    = tp->OtdrMode;
    StateCtrl->DataNum     = tp->DataNum;
	StateCtrl->FpgaTimeOut = 0;
    
/******************************** 初始化 StateCtrl.Measureparam ***********************************/
   	StateCtrl->MeasureParam.ChanNum         = tp->ChanNum;
   	StateCtrl->MeasureParam.Lambda_nm       = tp->Lambda_nm;
   	StateCtrl->MeasureParam.MeasureLength_m = tp->MeasureLength_m;
   	StateCtrl->MeasureParam.PulseWidth_ns   = tp->PulseWidth_ns;
   	StateCtrl->MeasureParam.MeasureTime_ms  = 400;
   	StateCtrl->MeasureParam.n               = tp->n;
   	StateCtrl->MeasureParam.EndThreshold    = tp->EndThreshold;
   	StateCtrl->MeasureParam.NonReflex       = tp->NonReflex;
    
    // 根据光纤长度匹配采样率和脉冲周期
    ModifyMeasureLength_PulseWidth(StateCtrl);
    AdaptSampleFreq_PulsePeriod(StateCtrl);
    PowerModeInit(StateCtrl);
    OtdrStateInit(StateCtrl);
}

int OtdrUpdateParamConnectState(OtdrStateCtrl_t *StateCtrl, OtdrTestParam_t *tp)
{
    int i = GetMeasureLengthIndex(tp->MeasureLength_m);

    if(i == -1)     return E_TEST_PARAM;
/************************************** 更新 StateCtrl ********************************************/
   	StateCtrl->OtdrMode    = tp->OtdrMode;
    StateCtrl->DataNum     = tp->DataNum;
	StateCtrl->FpgaTimeOut = 0;
    
/******************************** 初始化 StateCtrl.Measureparam ***********************************/
   	StateCtrl->MeasureParam.ChanNum         = tp->ChanNum;
   	StateCtrl->MeasureParam.Lambda_nm       = tp->Lambda_nm;

    // if measurelegnth is NOT 0, then do NOTHING
    StateCtrl->MeasureParam.MeasureLength_m = tp->MeasureLength_m;   // Auto measure param
    StateCtrl->MeasureParam.PulseWidth_ns   = OtdrCSPulseWidth[i];
   	StateCtrl->MeasureParam.MeasureTime_ms  = 400;
   	StateCtrl->MeasureParam.n               = tp->n;
   	StateCtrl->MeasureParam.EndThreshold    = tp->EndThreshold;
   	StateCtrl->MeasureParam.NonReflex       = tp->NonReflex;
    
    // 根据光纤长度匹配采样率和脉冲周期
    AdaptSampleFreq_PulsePeriod(StateCtrl);
    PowerModeInit(StateCtrl);
    OtdrStateInit(StateCtrl);
    return E_CMD_OK;
}

void OtdrUpdateParamSpTest(OtdrStateCtrl_t *StateCtrl, OtdrSpTestParam_t *tp)
{
/************************************** 更新 StateCtrl ********************************************/
    StateCtrl->OtdrMode = OTDR_MODE_AVG;
    StateCtrl->DataNum = tp->DataNum;
    
    StateCtrl->PulsePeriod_us = 1000;
	StateCtrl->FpgaTimeOut = 0;

/************************************** 初始化 StateCtrl.Measureparam *****************************************/
   	StateCtrl->MeasureParam.ChanNum         = tp->ChanNum;
   	StateCtrl->MeasureParam.Lambda_nm       = tp->Lambda_nm;
   	StateCtrl->MeasureParam.MeasureLength_m = tp->MeasureLength_m;
   	StateCtrl->MeasureParam.PulseWidth_ns   = tp->PulseWidth_ns;
   	StateCtrl->MeasureParam.MeasureTime_ms  = tp->MeasureTime_ms;
    
    AdaptSampleFreq_PulsePeriod(StateCtrl);
}

/*
 **************************************************************************************************
 *  函数  名： CheckIfAutoPower             CheckIfFindSmallEvent
 *  函数描述： 
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2012-12-28  17:10:33  v1.0
 **************************************************************************************************
*/
static int CheckIfFindSmallEvent(OtdrStateCtrl_t *StateCtrl)
{
    // 不拼接，并且M值较小时，才找小事件
    return (StateCtrl->ConcatParam.PowerMode != POWER_MODE_CONCAT) && (StateCtrl->M <= 16);
}

int CheckIfAutoPower(OtdrStateCtrl_t *StateCtrl)
{
    int AdaptPower;
    
    if(CC)  AdaptPower = 1;
    else    AdaptPower = 0;
    
    return AdaptPower;
}

int CheckIfGetConcat(OtdrTestParam_t *tp, ConcatParam_t *cp)
{
    int result = 0;
    assert(tp != NULL);

    if((tp->MeasureLength_m >= 100000) && (tp->PulseWidth_ns >= MIN_PW_DATA_CONCAT)){
        if(cp == NULL)  result = 1;
        else{
            if(cp->PowerMode == POWER_MODE_CONCAT){
                result = ((cp->ConcatPoint >= 0) && (cp->ConcatPoint < tp->DataNum));
            }
        }
    }
    return result;
}

/*
 **************************************************************************************
 *  函数名称： CheckRunParamValid
 *  函数描述： 检查运行参数合法性
 *  入口参数： MeasureLength_m : 测量长度
 *             PulseWidth_ns   : 脉冲宽度
 *  返回参数： 0               : 非法
 *             1               : 合法
 *  日期版本： 2012-12-29 11:44:29
 **************************************************************************************
*/
int CheckRunParamValid(OtdrStateCtrl_t *StateCtrl)
{
    int index, valid = 0;
    int MeasureLength_m = StateCtrl->MeasureParam.MeasureLength_m;
    int PulseWidth_ns = StateCtrl->MeasureParam.PulseWidth_ns;

    if((StateCtrl->MeasureParam.n > 1.0) && (StateCtrl->MeasureParam.n < 2.0)){
        // 自动测试则不检查
        if(MeasureLength_m > 0){
            index = GetMeasureLengthIndex(MeasureLength_m);
            if(index == -1)     return valid;

            if((850 == StateCtrl->MeasureParam.Lambda_nm) || (1300 == StateCtrl->MeasureParam.Lambda_nm))
            {
                if((MeasureLength_m < 32000) && (PulseWidth_ns <= 1280))    valid = 1;
            }
            else
            {
                if((PulseWidth_ns >= OtdrMinAllowPulseWidth[index]) && (PulseWidth_ns <= OtdrMaxAllowPulseWidth[index]))    valid = 1;
            }
        }
        else   valid = 1;
    }

    return valid;
}

/*
 **************************************************************************************************
 *  函数  名： UseLowPowerMode
 *  函数描述： 丢弃大功率数据，改用小功率曲线代替
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2011-09-21  15:47:23  v1.0
 **************************************************************************************************
*/
static void UseLowPowerMode(ConcatParam_t *ConcatParam)
{
    // 不使用高功率数据，所以功率控制模式要变成低功率模式
    ConcatParam->PowerMode = POWER_MODE_LOW;
    ConcatParam->ConcatPoint = 0;
}

/*
 **************************************************************************************************
 *  函数  名： GetNfirWidth
 *  函数描述： 获取平均滤波的窗口宽度
 *  入口参数： PowerMode : 功率模式，在低功率时使用更强的滤波
 *  返回参数： m         : 滤波窗口宽度
 *  日期版本： 2013-01-11  09:13:02  v1.0
 **************************************************************************************************
*/
int GetNfirWidth(OtdrStateCtrl_t *StateCtrl)
{
    int m, PulseWidth_ns;
    
    m = StateCtrl->M;
    PulseWidth_ns = StateCtrl->MeasureParam.PulseWidth_ns;
    
	if((PulseWidth_ns > 2560) && (PulseWidth_ns <= 10240))      m /= 2;     // 2011-8-23 21:11:11
	if((PulseWidth_ns > 10240) && (PulseWidth_ns <= 20480))     m /= 4;     // 2011-8-23 21:11:13
	if(StateCtrl->MeasureParam.MeasureLength_m > 100000)         m *= 2;     // 2012-4-16 11:05:38
	
	// 低功率使用更强的滤波
//	if(POWER_MODE_LOW == PowerMode)     m *= 2;     // 2013-1-11 9:16:15
	
	return m;
}

/*
 ********************************************************************************
 *  函数名称 ： ProcessRefreshData
 *  函数描述 ： OtdrData : carries data to be processed
 *              Statectrl : state and ctrl variable
 *              result   : process result
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2016-10-24 15:52:38
 ********************************************************************************
*/
int ProcessRefreshData(OtdrData_t *OtdrData, OtdrStateCtrl_t *StateCtrl, OtdrTestResult_t *result)
{
	int   m, sigma, DataNum, err_no = E_CMD_OK;
	int   *An = NULL, lpd_valid = 0, hpd_valid = 0;
    char  timebuf[32];

    m1_print("\n*********************** OTDR Algorithm Processing Refresh Data ***********************\n");
    m1_print("ProcessRefreshData start at time: %s\n", CurrentDateTime(timebuf));
    m1_print("OtdrState.HighPowerTime = %d, OtdrState.LowPowerTime = %d\n", StateCtrl->HighPowerTime, StateCtrl->LowPowerTime);
    //m1_print("OtdrData.hp_time = %d, OtdrData.lp_time = %d, LowPowerDataChanged = %d\n", OtdrData->hp_time, OtdrData->lp_time, StateCtrl->LowPowerDataChanged);
    StateCtrl->TotalMeasureTime = StateCtrl->HighPowerTime + StateCtrl->LowPowerTime;

    if(StateCtrl->HighPowerTime > 0)    hpd_valid = 1;
    if(StateCtrl->LowPowerTime > 0)     lpd_valid = 1;

    if(hpd_valid)   An = OtdrData->hp;
    else            An = OtdrData->lp;
    DataNum = StateCtrl->DataNum;

/********************************** 曲线数据预处理 *************************************/
    RemoveBaseLine(An, DataNum, NOISE_NUM);
    EnlargeData(An, DataNum, StateCtrl->TotalMeasureTime);
    AdjustCurve(An, DataNum, StateCtrl->CurveStartPoint);
    GetSaturateThreshold(An, StateCtrl);
    DeleteOsc(An, DataNum, StateCtrl);
    sigma = RootMeanSquare(An, DataNum, NOISE_NUM-StateCtrl->M);
    m1_print("Refresh raw_sigma = %d\n", sigma);
    
/******************************** 数字滤波与电容补偿 ***********************************/
	m = GetNfirWidth(StateCtrl);   // 2013-1-11 9:17:01
	nfir(An, An, DataNum, m);  // 2011-7-4 11:37:27
    sigma = RootMeanSquare(An, DataNum, NOISE_NUM-StateCtrl->M);
    StateCtrl->sigma = sigma;
    m1_print("Refresh filtered_sigma = %d\n", sigma);
    
    CapacityLinearCompensate(An, DataNum, MAX(m, 128), sigma, StateCtrl);
    
/************************* 大功率曲线和小功率曲线进行拼接 ******************************/
    if(StateCtrl->ConcatParam.PowerMode == POWER_MODE_CONCAT){
        if(hpd_valid && lpd_valid)  err_no = OtdrConcatCurve(OtdrData, StateCtrl);
    }
/******************************* 计算对数衰减值 ****************************************/
    //if(err_no == E_CONCAT)  hpd_valid = 0;  // drop highpower data if E_CONCAT
    //if(err_no == E_CMD_OK || err_no == E_CONCAT){
    if(err_no == E_CMD_OK){
        FastLog10Vector2(OtdrData, DataNum, StateCtrl, (hpd_valid << 1) | lpd_valid);
#if 0
        {
            char filename[128];
            static int fileindex=0;
            sprintf(filename, "/mnt/nfs/data/concatcurve_%02d", fileindex);
            savefloat(filename, OtdrData->Ai, DataNum);
            fileindex++;

        }
#endif
/******************************** 分析测量结果 *****************************************/
        AnalyseMeasureResult(StateCtrl, OtdrData->Ai, NULL, result);
    }
    m1_print("ProcessRefreshData finish at time: %s\n", CurrentDateTime(timebuf));
    return err_no;
}

/*
 ********************************************************************************
 *  函数名称 ： ProcessFinalData
 *  函数描述 ： 处理最终数据，包含事件分析
 *  入口参数 ： OtdrData  : 输入的OTDR数据
 *              StateCtrl : 状态及控制变量
 *              result    : 处理的测试结果
 *  返回参数 ： 错误码：0为正常，其他请看相应的E_xxx
 *  日期版本 ： 2016-10-24 16:19:51
 ********************************************************************************
*/
int ProcessFinalData(OtdrData_t *OtdrData, OtdrStateCtrl_t *StateCtrl, OtdrTestResult_t *result, SaveRunningData_t *srd)
{
    extern void PrintOtdrStateCtrl(OtdrStateCtrl_t *StateCtrl);
	int   i, m, sigma, DataNum, FindSmallEvent, fc, err_no = E_CMD_OK;
	int   *An = NULL, lpd_valid = 0, hpd_valid = 0;
    char  DATE_TIME[20], param[64], fn[100], timebuf[32];
	time_t ct = time(NULL);
	struct tm *p = localtime(&ct);
    Event_t EventTempLarge, EventTempSmall;

	// 分配指针
    if(StateCtrl->HighPowerTime > 0)    hpd_valid = 1;
    if(StateCtrl->LowPowerTime > 0)     lpd_valid = 1;

    if(hpd_valid)   An = OtdrData->hp;
    else            An = OtdrData->lp;
    DataNum = StateCtrl->DataNum;

    if((StateCtrl->ConcatParam.PowerMode == POWER_MODE_CONCAT) &&
        (StateCtrl->HighPowerTime == 0))    StateCtrl->HpdValid = 0;
    else    StateCtrl->HpdValid = 1;

    //PrintOtdrStateCtrl(StateCtrl);

    m1_print("\n*********************** OTDR Algorithm Processing Final Data ***********************\n");
    m1_print("ProcessFinalData start at time: %s\n", CurrentDateTime(timebuf));
    m1_print("OtdrState.HighPowerTime = %d, OtdrState.LowPowerTime = %d\n", StateCtrl->HighPowerTime, StateCtrl->LowPowerTime);
    StateCtrl->TotalMeasureTime = StateCtrl->HighPowerTime + StateCtrl->LowPowerTime;
    
    FindSmallEvent = CheckIfFindSmallEvent(StateCtrl);

    sprintf(DATE_TIME, "%04d%02d%02d_%02d%02d%02d", p->tm_year+1900, \
            p->tm_mon+1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);

    sprintf(param, "%dnm%dkm%dns%dsP%dR%XV%d", StateCtrl->MeasureParam.Lambda_nm, \
                                               StateCtrl->MeasureParam.MeasureLength_m/1000, \
                                               StateCtrl->MeasureParam.PulseWidth_ns, \
                                               StateCtrl->TotalMeasureTime/1000, \
                                               StateCtrl->thisPower, \
                                               StateCtrl->thisRcv, \
                                               StateCtrl->thisApdV);

/**** check if it needs to save data ***************************************************/
    if(isSRDcode(srd, HP_RAW)){
        fc = HP_RAW;
        sprintf(fn, "otdr_hp%d_%s_%s", fc, DATE_TIME, param);
        putSRD(srd, fn, param, fc, An, DataNum);
    }

/********************************** 曲线数据预处理 *************************************/
    RemoveBaseLine(An, DataNum, NOISE_NUM);
    EnlargeData(An, DataNum, StateCtrl->TotalMeasureTime);
    AdjustCurve(An, DataNum, StateCtrl->CurveStartPoint);
    sigma = RootMeanSquare(An, DataNum, NOISE_NUM-StateCtrl->M);
    m1_info("Final Raw sigma = %d\n", sigma);
    
/**** check if it needs to save data ***************************************************/
    if(isSRDcode(srd, HP_ZERO_BASE)){
        fc = HP_ZERO_BASE;
        sprintf(fn, "otdr_hp%d_%s_%s", fc, DATE_TIME, param);
        putSRD(srd, fn, param, fc, An, DataNum);
    }

    if(GetSaturateThreshold(An, StateCtrl))
    {
        DeleteOsc(An, DataNum, StateCtrl);
    }
    GetCurveSaturatePoint(OtdrData, StateCtrl);

/**** check if it needs to save data ***************************************************/
    if(isSRDcode(srd, HP_DELETE_OSC)){
        fc = HP_DELETE_OSC;
        sprintf(fn, "otdr_hp%d_%s_%s", fc, DATE_TIME, param);
        putSRD(srd, fn, param, fc, An, DataNum);
    }

/******************************** 数字滤波与电容补偿 ***********************************/
	m = GetNfirWidth(StateCtrl);   // 2013-1-11 9:17:01
	nfir(An, An, DataNum, m);  // 2011-7-4 11:37:27
    sigma = RootMeanSquare(An, DataNum, NOISE_NUM-StateCtrl->M);
    StateCtrl->sigma = sigma;
    m1_info("Final Filtered sigma = %d\n", sigma);
    
/**** check if it needs to save data ***************************************************/
    if(isSRDcode(srd, HP_FILTERED)){
        fc = HP_FILTERED;
        sprintf(fn, "otdr_hp%d_%s_%s", fc, DATE_TIME, param);
        putSRD(srd, fn, param, fc, An, DataNum);
    }

    CapacityLinearCompensate(An, DataNum, MAX(m, 128), sigma, StateCtrl);
/**** check if it needs to save data ***************************************************/
    if(isSRDcode(srd, HP_COMPENSATE)){
        fc = HP_COMPENSATE;
        sprintf(fn, "otdr_hp%d_%s_%s", fc, DATE_TIME, param);
        putSRD(srd, fn, param, fc, An, DataNum);
    }

/************************* 大功率曲线和小功率曲线进行拼接 ******************************/
    if(StateCtrl->ConcatParam.PowerMode == POWER_MODE_CONCAT){
        if(hpd_valid && lpd_valid)  err_no = OtdrConcatCurve(OtdrData, StateCtrl);
/**** check if it needs to save data ***************************************************/
        if(isSRDcode(srd, LP_RAW)){
            fc = LP_RAW;
            sprintf(fn, "otdr_lp501_%s_%s", DATE_TIME, param);
            putSRD(srd, fn, param, fc, OtdrData->lp, DataNum);
        }
    }
    
/******************************* 计算对数衰减值 ****************************************/
    if(err_no == E_CMD_OK){
        FastLog10Vector2(OtdrData, DataNum, StateCtrl, (hpd_valid << 1) | lpd_valid);
/**** check if it needs to save data ***************************************************/
        if(isSRDcode(srd, OTDR_LOG)){
            fc = OTDR_LOG;
            sprintf(fn, "otdr_log_%s_%s", DATE_TIME, param);
            putSRD(srd, fn, param, fc, OtdrData->Ai, DataNum);
        }
/****************************** 寻找事件点 *****************************************/
        EventMalloc(&EventTempLarge, DataNum);
        if(0.0 == StateCtrl->MeasureParam.NonReflex){
            FindLargeEventsBeforeLog(OtdrData, &EventTempLarge, StateCtrl);
            if(FindSmallEvent){
                EventMalloc(&EventTempSmall, DataNum);
                FindSmallEventsBeforeLog(OtdrData, &EventTempLarge, StateCtrl);
            }
        }
        else{
            FindLargeEventsAfterLog(OtdrData, &EventTempLarge, StateCtrl);
            if(FindSmallEvent){
                EventMalloc(&EventTempSmall, DataNum);
                FindSmallEventsAfterLog(OtdrData, &EventTempLarge, StateCtrl);
            }
        }
/******************************** 事件点过滤 *******************************************/
        EventPointsFilter(OtdrData, &EventTempLarge, "Large", StateCtrl); 
        if(FindSmallEvent)      // 2011-8-23 21:07:27
        {
            EventPointsFilter(OtdrData, &EventTempSmall, "Small", StateCtrl); 
            i = EventTempLarge.FinalEventNum;
            MergeFinalEvents(&EventTempLarge, &EventTempSmall,StateCtrl);     
            EventFree(&EventTempSmall);                         
            m1_print("2nd Add %d Events\n", EventTempLarge.FinalEventNum-i);
        }

        // 事件点划分
        FindSaturateEvents(An, &EventTempLarge, StateCtrl->SatThreshold);  // 寻找饱和事件点
        SplitFinalEvents(OtdrData->Ai, DataNum, &EventTempLarge, StateCtrl);

        FindSaturateEvents(An, &EventTempLarge, StateCtrl->SatThreshold);  // 寻找饱和事件点
        RemoveTailNonReflexEventPoint(OtdrData, &EventTempLarge, StateCtrl);
        RemoveLowLevelEventPoint(OtdrData, &EventTempLarge, StateCtrl);
        RemoveConcatPointEventPoint(OtdrData, &EventTempLarge, StateCtrl);
/******************************** 确定结束事件点 ***************************************/
        FindProbableEndEvent(OtdrData, &EventTempLarge, StateCtrl);
        FindSaturateEvents(An, &EventTempLarge, StateCtrl->SatThreshold);  // 寻找饱和事件点
        FindEndEventPoint(OtdrData, &EventTempLarge, StateCtrl);
/******************************** 分析测量结果 *****************************************/
        AnalyseMeasureResult(StateCtrl, OtdrData->Ai, &EventTempLarge, result);
        EventFree(&EventTempLarge);                         
    }
    m1_print("ProcessFinalData finish at time: %s\n", CurrentDateTime(timebuf));
    return err_no;
}

/*
 ********************************************************************************
 *  函数名称 ： ProcessSpData
 *  函数描述 ： 复制数据到结果变量
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2016-11-09 09:39:41
 ********************************************************************************
*/
int ProcessSpData(OtdrData_t *OtdrData, OtdrSpTestParam_t *sp, OtdrSpTestResult_t *result)
{
	int   i;

    m1_print("\n*********************** Processing SpTest Data ***********************\n");
    m1_print("SpTestParam : %dnm-%dkm-%dns-%ds, Power = %d, Rcv = 0x%X, ApdV = %d\n", 
            sp->Lambda_nm, sp->MeasureLength_m/1000, sp->PulseWidth_ns, sp->MeasureTime_ms,
            sp->powerlevel, sp->rcv, sp->apdv);

/********************************** 复制测试参数 *************************************/
    memcpy(&result->sp, sp, sizeof(OtdrSpTestParam_t));

/********************************** 复制曲线数据 *************************************/
    for(i = 0; i < sp->DataNum; i++){
        result->data[i] = OtdrData->hp[i];
    }
    return E_CMD_OK;
}

/*
 **************************************************************************************************
 *  函数  名： EstimateFiberLen
 *  函数描述： 根据测试的数据来估计光纤长度
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2012-12-28  15:23:19  v1.0
 **************************************************************************************************
*/
float EstimateFiberLen(OtdrStateCtrl_t *StateCtrl, OtdrData_t *OtdrData)
{
	int   m, i, sigma, DataNum = StateCtrl->DataNum, *An = OtdrData->hp;
	
	StateCtrl->M = PulseWidthInSampleNum(StateCtrl);
	StateCtrl->Points_1m = 2*StateCtrl->MeasureParam.n * StateCtrl->RealSampleRate_Hz /C;
/********************************** 曲线数据预处理 *************************************/
    RemoveBaseLine(An, DataNum, NOISE_NUM);
    EnlargeData(An, DataNum, StateCtrl->MeasureParam.MeasureTime_ms);
    AdjustCurve(An, DataNum, StateCtrl->CurveStartPoint);
    GetSaturateThreshold(An, StateCtrl);
/******************************** 数字滤波与电容补偿 ***********************************/
	m = GetNfirWidth(StateCtrl);   // 2013-1-11 9:17:01
	nfir(An, An, DataNum, m);  // 2011-7-4 11:37:27
    sigma = RootMeanSquare(An, DataNum, NOISE_NUM-StateCtrl->M);
    StateCtrl->sigma = sigma;
    
    CapacityLinearCompensate(An, DataNum, MAX(m, 128), sigma, StateCtrl);
/******************************** 计算信号结束点 ***************************************/
	StateCtrl->SignalEndPoint = FastEstimateFiber(OtdrData, DataNum, sigma, StateCtrl);
	
	// 返回结束点处的dB值
	i = MAX(StateCtrl->M, StateCtrl->SignalEndPoint - StateCtrl->M);
	MeanValue(An, i, StateCtrl->SignalEndPoint, &m, DATA_TYPE_INT);
	StateCtrl->AutoEndLevel = 5*FastLog10((float)m / sigma);

	return (StateCtrl->SignalEndPoint / StateCtrl->Points_1m);
}

/*
 **************************************************************************************************
 *  函数  名： EstimateCurveConcat
 *  函数描述： 根据测试的数据来估计是否需要进行曲线拼接
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2012-12-31  14:50:02  v1.0
 **************************************************************************************************
*/
void EstimateCurveConcat(OtdrStateCtrl_t *StateCtrl, OtdrData_t *OtdrData, ConcatParam_t *ConcatParam)
{
	int   m, i, avg, sigma, Cn, accept, mode_undef = 1, FrontFlat = 0, fiberlessthan30km = 0;
	int   *An = NULL, DataNum = StateCtrl->DataNum;
	int  PulseWidth_ns, Lambda_nm, CurveConcatPoint;
	float   v, k;

	// 分配指针
	An = OtdrData->hp;

    Lambda_nm = StateCtrl->MeasureParam.Lambda_nm;
    PulseWidth_ns = StateCtrl->MeasureParam.PulseWidth_ns;
/********************************** 曲线数据预处理 *************************************/
    RemoveBaseLine(An, DataNum, NOISE_NUM);
    EnlargeData(An, DataNum, 128);
    AdjustCurve(An, DataNum, StateCtrl->CurveStartPoint);
    i = GetSaturateThreshold(An, StateCtrl);
    //debug
    if(i == 0)
    {
        m1_warning("NOT found saturation\n");
    }
/******************************** 数字滤波与电容补偿 ***********************************/
	m = GetNfirWidth(StateCtrl);   // 2013-1-11 9:17:01
	nfir(An, An, DataNum, m);  // 2011-7-4 11:37:27
    sigma = RootMeanSquare(An, DataNum, NOISE_NUM-StateCtrl->M);
    StateCtrl->sigma = sigma;
    
    CapacityLinearCompensate(An, DataNum, MAX(m, 128), sigma, StateCtrl);
/****************************** 判断大功率信号是否需要拼接 *****************************/
    // 首先检测光纤是否长于30km
    {
        int Pos5dB, tmp;
        
        Cn = (int)(StateCtrl->Points_1m * 30000);
        MeanValue(An, Cn-20, Cn+20, &avg, DATA_TYPE_INT);
        
        // 从前向后寻找低于5dB的点
        Pos5dB = DataNum;
        tmp = Tenth_div5(6.0) * sigma;
        for(i = StateCtrl->M; i < DataNum; i++)
        {
            if(An[i] <= tmp)
            {
                Pos5dB = i;
                break;
            }
        }
        
        if((avg < sigma*Tenth_div5(5)) || (Cn > Pos5dB))   // 高于5dB
        {
            fiberlessthan30km = 1;
        }
    }
    
    // 然后判断大功率曲线的前端是否平顶
    {
        int temp, cc = 0;
        
        // 按线性递增律估计当前脉宽的盲区，并转换成点数
        Cn = GetPulseWidthSaturateBlindZone(Lambda_nm, PulseWidth_ns);
        Cn = (int)(StateCtrl->Points_1m * Cn);
        
        // 看该点之后是否存在饱和值
        temp = StateCtrl->SatThreshold;
        cc = 0;
        for(i = Cn+5; i < Cn+200; i++)
        {
            if(An[i] >= temp)
            {
                if(++cc > 10)
                {
                    FrontFlat = 1;
                    break;
                }
            }
            else    cc = 0;     // 2016年 10月 21日 星期五 17:26:58 CST
        }
        
        // 如果前端平顶，则寻找拼接点
        if(FrontFlat)
        {
            // 前端平顶，如果光纤长度长于30km，则需要拼接，否则使用低功率，同时低功率曲线需要上抬5dB
            if(fiberlessthan30km)
            {
                UseLowPowerMode(ConcatParam);
                m1_warning("front saturate and fiberlessthan30km, use low power mode\n");
                mode_undef = 0;
                return;
            }
            else
            {
                m = PulseWidthInSampleNum(StateCtrl);
                for(i = Cn+10; i < DataNum; i++)
                {
                    if(An[i] < StateCtrl->SatThreshold)
                    {
                        // 平顶开始的位置是Cn+5，把它保存在低16位中，平顶结束的位置是i，把它保存在高16位中
                        CurveConcatPoint = i + (int)(StateCtrl->Points_1m * 4000);  // 记下拼接点，在当前点后4公里处
                        CurveConcatPoint = MAX(CurveConcatPoint, i+3*m);  // 而且不能短于3m
                        
                        // 该点不能太远
                        if((CurveConcatPoint >= StateCtrl->MeasureLengthPoint*8/10) ||
                           (CurveConcatPoint >= DataNum - 6*m))
                        {
                            UseLowPowerMode(ConcatParam);
                            m1_warning("concatenate point is too far away, use low power mode\n");
                            mode_undef = 0;
                            return;
                        }
                        break;
                    }
                }
            }
        }
        else    // 前端未平顶，使用大功率模式
        {
            ConcatParam->PowerMode = POWER_MODE_HIGH;
            ConcatParam->ConcatPoint = 0;
            m1_warning("front not saturate, use high power mode\n");
            mode_undef = 0;
            return;
        }
    }
/*************************** 进一步考察该拼接点是否合理 ********************************/
    // 拼接点处不能存在事件点
    if(mode_undef)
    {
        find_event_param_t fep;
        Cn = CurveConcatPoint;
        GetEventFindingParamBeforeLog(&fep, "Large", StateCtrl);
        k = fep.k;
        m = fep.M;
        k = k*m;
        while((Cn < StateCtrl->MeasureLengthPoint*8/10) && (Cn < DataNum - 6*m))
        {
            accept = 1;
            for(i = Cn-m/2; i < Cn+m/2; i++)
            {
                if((An[i] < sigma) || (An[i+m] < sigma))    // fall to noise, denied
                {
                    accept = -1;
                    break;
                }
                v = (float)An[i] / An[i+m];
            	v = 5* FastLog10(v) - k;
            	
            	if(fabs(v) > 0.5)     // 如果增量函数太大，超过0.5dB，则表明有事件点，往后走m点
            	{
            	    accept = 0;
            	    break;
            	}
            }
            if(1 == accept)
            {
                ConcatParam->PowerMode = POWER_MODE_CONCAT;
                ConcatParam->ConcatPoint = Cn;
                mode_undef = 0;
                break;
            }
            else if(-1 == accept)
            {
                UseLowPowerMode(ConcatParam);
                m1_warning("can't find a proper connection point, use low power mode\n");
                mode_undef = 0;
                return;
            }
            else    Cn += m;
        }
    }
    
    // 拼接点处的 lowpowerdata 强度必须高于 15dB
    
    // 如果到达这里，表明需要拼接的所有条件都满足
    if(mode_undef){
        ConcatParam->PowerMode = POWER_MODE_LOW;
        ConcatParam->ConcatPoint = 0;
        m1_warning("mode_undef, use LowPower mode!!!\n");
    }
    else{
        m1_info("concatenate point = %d(%.3fkm)\n", ConcatParam->ConcatPoint,
                (float)ConcatParam->ConcatPoint/StateCtrl->Points_1m/1000);
    }
}

/*
 **************************************************************************************************
 *  函数  名： CheckIfFrontSaturate
 *  函数描述： 根据测试的数据来判断曲线是否在指定长度内平顶
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2013-12-6 14:41:35
 **************************************************************************************************
*/
int CheckIfFrontSaturate(OtdrData_t *OtdrData, OtdrStateCtrl_t *StateCtrl, int FrontLen)
{
	int   i, cc, FrontFlat = 0;
	int   *An = NULL;

	// 分配指针
	An = OtdrData->hp;
/********************************** 曲线数据预处理 *************************************/
    AdjustCurve(An, StateCtrl->DataNum, StateCtrl->CurveStartPoint);
    i = GetSaturateThreshold(An, StateCtrl);
    
    if(i == 0)  // 未找到平顶，表明曲线不平顶
    {
        m1_warning("NOT found saturation when CheckIfFrontSaturate\n");
    }
    else
    {
/********************************** 判断曲线前端是否平顶 *******************************/
        cc = 0;
        for(i = 0; i < FrontLen; i++)
        {
            if(An[i] >= StateCtrl->SatThreshold)
            {
                if(++cc > 10)
                {
                    FrontFlat = 1;
                    break;
                }
            }
        }
    }
    return FrontFlat;
}

/*
 **************************************************************************************************
 *  函数  名： EstimateConnectState
 *  函数描述： 估计光纤连接状态
 *  入口参数： 
 *  返回参数： 
 *  日期版本： 2016年 10月 27日 星期四 11:10:05 CST
 **************************************************************************************************
*/
int EstimateConnectState(OtdrStateCtrl_t *StateCtrl, OtdrData_t *OtdrData)
{
	int   i, cc = 0, DataNum = StateCtrl->DataNum, *An = OtdrData->hp;
	
/********************************** 曲线数据预处理 *************************************/
    RemoveBaseLine(An, DataNum, NOISE_NUM);
    AdjustCurve(An, DataNum, StateCtrl->CurveStartPoint);
    i = GetSaturateThreshold(An, StateCtrl);
    if(i == 0)  // 未找到平顶，表明曲线不平顶
    {
        m1_warning("NOT found saturation when EstimateConnectState\n");
    }
    else
    {
/********************************** 判断曲线前端是否平顶 *******************************/
        for(i = 0; i < 10*StateCtrl->M; i++)
        {
            if(An[i] >= StateCtrl->SatThreshold)
            {
                cc++;
            }
        }
    }
	return (cc <= StateCtrl->M) ? 1 : 2;
}

/*
 **************************************************************************************
 *    End    of    File
 **************************************************************************************
*/
